package base.core.excel;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.read.metadata.ReadSheet;

import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import base.core.util.Beans;

/**
 * @Description https://github.com/alibaba/easyexcel/blob/master/quickstart.md#exceptionRead
 * @Author Danny Pengwei
 * @CreatDate 2019/9/29 16:23
 */
public class ExcelRead {

    public class Reader {
        List<ReadSheet> sheetList = new ArrayList<>();
        ExcelReader excelReader;

        public Reader(ExcelReader excelReader) {
            this.excelReader = excelReader;
        }

        public <T> List<T> sheet(Class<T> aClass, Integer sheetNo) {
            List<T> list = new ArrayList<>();
            sheetList.add(EasyExcel.readSheet(sheetNo).head(aClass).registerReadListener(new ExcelListener<T>((o, analysisContext, excelListener) -> {
                list.add(o);
            })).build());
            return list;
        }

        public <T> List<T> sheet(Class<T> aClass, String sheetName) {
            List<T> list = new ArrayList<>();
            sheetList.add(EasyExcel.readSheet(sheetName).head(aClass).registerReadListener(new ExcelListener<T>((o, analysisContext, excelListener) -> {
                list.add(o);
            })).build());
            return list;
        }

        public <T> List<T> sheet(Class<T> aClass) {
            List<T> list = new ArrayList<>();
            sheetList.add(EasyExcel.readSheet(0).head(aClass).registerReadListener(new ExcelListener<T>((o, analysisContext, excelListener) -> {
                list.add(o);
            })).build());
            return list;
        }

        public void read() {
            excelReader.read(sheetList);
            excelReader.finish();
        }
    }

    public Reader reader(InputStream inputStream) throws IOException {
        ExcelReader excelReader = EasyExcel.read(inputStream).build();
        return new Reader(excelReader);
    }


    /**
     * 同步读
     */
    public static <T> List<T> readSync(InputStream inputStream, Class<T> aClass) {
       return readSync(inputStream, aClass,null, null);
    }
    /**
     * 同步读
     */
    public static <T> List<T> readSync(InputStream inputStream, Class<T> aClass, Integer headRowNumber) {
        return readSync(inputStream,aClass, headRowNumber, null);
    }

    public static <T> List<T> readSync(InputStream inputStream,  Class<T> aClass,Integer headRowNumber, Integer sheet) {
        try {
            List<T> list = new ArrayList<>();
            ExcelRead.read(inputStream,aClass,headRowNumber,sheet,new ExcelListener<>((t, analysisContext, excelListener1) -> {
                list.add(t);
            }));
            return list;
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    public static <T> void read(InputStream inputStream, Class<T> aClass, ExcelListener<T> excelListener) {
        try {
            EasyExcel.read(inputStream, aClass, excelListener).sheet().doRead();
        } catch (Exception e) {
            e.printStackTrace();
            if (!excelListener.isStoped()) {
                throw new RuntimeException(e.getMessage());
            }
        }
    }

    public static <T> void read(InputStream inputStream, Class<T> aClass, Integer headerNum, ExcelListener<T> excelListener) {
        try {
            EasyExcel.read(inputStream, aClass, excelListener).sheet().headRowNumber(headerNum).doRead();
        } catch (Exception e) {
            e.printStackTrace();
            if (!excelListener.isStoped()) {
                throw new RuntimeException(e.getMessage());
            }
        }
    }

    public static <T> void read(InputStream inputStream, Class<T> aClass,Integer headerNum,Integer sheet, ExcelListener<T> excelListener) {
        try {
            EasyExcel.read(inputStream, aClass, excelListener).sheet(sheet).headRowNumber(headerNum).doRead();
        } catch (Exception e) {
            e.printStackTrace();
            if (!excelListener.isStoped()) {
                throw new RuntimeException(e.getMessage());
            }
        }
    }

    public static class ExcelListener<T> extends AnalysisEventListener<T> {
        Object object;
        Listener<T> listener;
        boolean stoped = false;

        public ExcelListener(Listener<T> listener) {
            this.listener = listener;
        }

        @Override
        public void invoke(T t, AnalysisContext analysisContext) {
            if (isNotEmpty(t)) {
                listener.invoke(t, analysisContext, this);
            }
        }

        @Override
        public void doAfterAllAnalysed(AnalysisContext context) {
        }

        public <T> T getObject() {
            return (T) object;
        }

        public void setObject(Object object) {
            this.object = object;
        }

        public void stop() {
            stoped = true;
            throw new RuntimeException();
        }

        public void stop(Object object) {
            stoped = true;
            this.object = object;
            throw new RuntimeException();
        }

        public boolean isStoped() {
            return stoped;
        }

    }

    public interface Listener<T> {
        void invoke(T t, AnalysisContext analysisContext, ExcelListener<T> excelListener);
    }

    // excel解析的一行的实体是否为空
    public static boolean isNotEmpty(Object object) {
        HashMap hashMap = Beans.asObj(object, HashMap.class);
        if (CollectionUtils.isEmpty(hashMap)) {
            return false;
        }
        Collection values = hashMap.values();
        if (CollectionUtils.isEmpty(values)) {
            return false;
        }
        Object obj = values.stream().filter(v -> {
                    if (v == null) {
                        return false;
                    }
                    if (v instanceof String) {
                        return StringUtils.isNotBlank(v.toString());
                    }
                    if (v.getClass().isArray()) {
                        return ((Object[]) v).length != 0;
                    }
                    if (v instanceof Collection) {
                        return ((Collection) v).size() != 0;
                    }
                    if (v instanceof Map) {
                        return ((Map) v).size() != 0;
                    }
                    return v != null;
                }
        ).findAny().orElse(null);
        return obj != null;
    }

}